package com.yuyuan.blog.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.yuyuan.blog.domain.Event;
import com.yuyuan.blog.domain.dto.BlogAgreementDTO;
import com.yuyuan.blog.domain.po.BlogAgreement;
import com.yuyuan.blog.event.EventBlogProducer;
import com.yuyuan.blog.mapper.AgreementBlogMapper;
import com.yuyuan.blog.service.IAgreementBlogService;
import com.yuyuan.blog.service.IElasticSearch;
import com.yuyuan.blog.utils.IdGenerator;
import com.yuyuan.blog.utils.MyUtils;
import com.yuyuan.blog.utils.SensitiveFilter;
import com.yuyuan.common.domain.Result;
import com.yuyuan.common.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;


import static com.yuyuan.blog.utils.CommunityConstant.*;
import static com.yuyuan.common.utils.RedisConstants.BLOG_PUBLISH_LOCK;
import static com.yuyuan.common.utils.RedisConstants.BLOG_UPDATE_LOCK;

/**
 * @Author: kestrel
 * @Version:1.0
 * @Date: 2024/5/29
 */
@Slf4j
@Service
public class AgreementBlogServiceImpl extends ServiceImpl<AgreementBlogMapper, BlogAgreement> implements IAgreementBlogService {
    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private AgreementBlogMapper agreementBlogMapper;

    @Autowired
    private EventBlogProducer eventBlogProducer;

    @Autowired
    private IElasticSearch elasticSearch;

    @Autowired
    private MyUtils myUtils;

    @Autowired
    private SensitiveFilter sensitiveFilter;

    @Override
    public Result publishAgreement(BlogAgreementDTO blogAgreementDTO, Short blogType) throws InterruptedException {
        Long userId = UserHolder.getUser().getId();
        //加入分布式锁(解决单个用户发帖时发生线程安全问题)
        RLock lock = redissonClient.getLock(BLOG_PUBLISH_LOCK + userId);
        //尝试获取锁，无等待时间，无限释放时间(含看门狗机制)
        boolean isSuccess = lock.tryLock(1, TimeUnit.SECONDS);
        //获取锁失败
        if (!isSuccess) {
            return Result.fail("发帖太频繁了哦~请稍后再试!");
        }
        BlogAgreement blogAgreement = BeanUtil.copyProperties(blogAgreementDTO, BlogAgreement.class);
        blogAgreement.setId(idGenerator.nextBlogId(blogType));
        blogAgreement.setUserId(userId);
        blogAgreement.setUserName(UserHolder.getUser().getNickName());
        blogAgreement.setIcon(UserHolder.getUser().getIcon());
        LocalDateTime now = LocalDateTime.now();
        blogAgreement.setCreateTime(now);
        blogAgreement.setUpdateTime(now);
        blogAgreement.setAgreementType(blogType);
        // 过滤敏感词
        blogAgreement.setName(sensitiveFilter.filter(blogAgreement.getName()));
        blogAgreement.setContent(sensitiveFilter.filter(blogAgreement.getContent()));

        agreementBlogMapper.insert(blogAgreement);

        // 触发发帖事件，存到ES服务器
        Event event = new Event(
                TOPIC_PUBLIC,
                UserHolder.getUser().getId(),
                ENTITY_TYPE_POST,
                blogAgreement.getId(),
                blogAgreement,
                "BlogAgreement");
        eventBlogProducer.fireEvent(event);

        lock.unlock();
        return Result.ok(blogAgreement);
    }

    @Override
    public Result updateAgreement(BlogAgreementDTO blogAgreementDTO, Long blogId) throws InterruptedException {
        Long userId = UserHolder.getUser().getId();
        //加入分布式锁(解决单个用户发帖时发生线程安全问题)
        RLock lock = redissonClient.getLock(BLOG_UPDATE_LOCK + userId);
        //尝试获取锁，无等待时间，无限释放时间(含看门狗机制)
        boolean isSuccess = lock.tryLock(1, TimeUnit.SECONDS);
        //获取锁失败
        if (!isSuccess) {
            return Result.fail("更帖太频繁了哦~请稍后再试!");
        }
        BlogAgreement blogAgreement = BeanUtil.copyProperties(blogAgreementDTO, BlogAgreement.class);
        blogAgreement.setId(blogId);
        LocalDateTime now = LocalDateTime.now();
        blogAgreement.setUpdateTime(now);
        agreementBlogMapper.updateById(blogAgreement);

        // 触发删帖事件，删除ES服务器内容
        Event event = new Event(
                TOPIC_UPDATE,
                UserHolder.getUser().getId(),
                ENTITY_TYPE_POST,
                blogAgreement.getId(),
                blogAgreement,
                "BlogAgreement");
        eventBlogProducer.fireEvent(event);

        lock.unlock();
        return Result.ok(blogAgreement);
    }

    @Override
    public Result getSingleAgreement(Short blogType, Long blogId) {
        return Result.ok(agreementBlogMapper.selectById(blogId));
    }

    @Override
    public Result getAgreement(Short blogType, Long startId) {
        //分页查询传入0时默认读取最新(最迟创建)数据，进行处理
        startId = myUtils.zeroHandler(startId, Long.valueOf(blogType), "BlogAgreement");
        List<BlogAgreement> list = agreementBlogMapper.getAgreements(blogType,startId);
        for (BlogAgreement blogAgreement : list) {
            //处理贴子图片临时链接
            blogAgreement.handlerImgs();
        }
        //返回结果，以及长度
        return Result.ok(list,((Integer)list.size()).longValue());
    }

    @Override
    public Result getSearchAgreements(String searchKeyWord, Short type, Short blogType) throws IOException {
        return elasticSearch.searchAgreementBlog(searchKeyWord, blogType);
    }
}
